package utn.frba.matematicasuperior.controladores;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Cursor;
import javafx.scene.control.Button;
import javafx.scene.control.Dialogs;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.util.Callback;
import utn.frba.matematicasuperior.main.Main;
import utn.frba.matematicasuperior.modelo.ParOrdenado;
import utn.frba.matematicasuperior.utiles.CeldaEditableDouble;
import utn.frba.matematicasuperior.utiles.CheckBoxCell;
import utn.frba.matematicasuperior.utiles.Controlador;

public class SoporteControlador implements Controlador {

	/************************************************************/
	/************************ ATRIBUTOS *************************/
	/************************************************************/

	private Main main;

	@FXML
	private Button btnAgregarParOrdenado;

	@FXML
	private Button btnLimpiarParesSeleccionados;

	private ObservableList<ParOrdenado> soporteData = FXCollections
			.observableArrayList();

	@FXML
	private TableView<ParOrdenado> tablaSoporte;

	@FXML
	private TableColumn<ParOrdenado, Double> columnaX;

	@FXML
	private TableColumn<ParOrdenado, Double> columnaY;

	@FXML
	private TableColumn<ParOrdenado, Boolean> columnaCheckbox;

	@FXML
	private TextField textFieldX;

	@FXML
	private TextField textFieldY;

	/************************************************************/
	/*********************** PROPIEDADES ************************/
	/************************************************************/

	public Button getBtnLimpiarParesSeleccionados() {
		return btnLimpiarParesSeleccionados;
	}

	public void setBtnLimpiarParesSeleccionados(
			Button btnLimpiarParesSeleccionados) {
		this.btnLimpiarParesSeleccionados = btnLimpiarParesSeleccionados;
	}

	public TableColumn<ParOrdenado, Boolean> getColumnaCheckbox() {
		return columnaCheckbox;
	}

	public void setColumnaCheckbox(
			TableColumn<ParOrdenado, Boolean> columnaCheckbox) {
		this.columnaCheckbox = columnaCheckbox;
	}

	public TextField getTextFieldX() {
		return textFieldX;
	}

	public void setTextFieldX(TextField textFieldX) {
		this.textFieldX = textFieldX;
	}

	public TextField getTextFieldY() {
		return textFieldY;
	}

	public void setTextFieldY(TextField textFieldY) {
		this.textFieldY = textFieldY;
	}

	public Button getBtnAgregarParOrdenado() {
		return btnAgregarParOrdenado;
	}

	public void setBtnAgregarParOrdenado(Button btnAgregarParOrdenado) {
		this.btnAgregarParOrdenado = btnAgregarParOrdenado;
	}

	public Main getMain() {
		return main;
	}

	public void setMain(Main main) {
		this.main = main;
	}

	public ObservableList<ParOrdenado> getSoporteData() {
		return soporteData;
	}

	public void setSoporteData(ObservableList<ParOrdenado> soporteData) {
		this.soporteData = soporteData;
	}

	public TableView<ParOrdenado> getTablaSoporte() {
		return tablaSoporte;
	}

	public void setTablaSoporte(TableView<ParOrdenado> tablaSoporte) {
		this.tablaSoporte = tablaSoporte;
	}

	public TableColumn<ParOrdenado, Double> getColumnaX() {
		return columnaX;
	}

	public void setColumnaX(TableColumn<ParOrdenado, Double> columnaX) {
		this.columnaX = columnaX;
	}

	public TableColumn<ParOrdenado, Double> getColumnaY() {
		return columnaY;
	}

	public void setColumnaY(TableColumn<ParOrdenado, Double> columnaY) {
		this.columnaY = columnaY;
	}

	/************************************************************/
	/*********************** CONSTRUCTOR ************************/
	/************************************************************/

	/************************************************************/
	/********************* EVENTS HANDLERS **********************/
	/************************************************************/

	@FXML
	private void initialize() {
		configurarTablaSoporte();
	}

	@FXML
	private void handleAgregarParOrdenado() {

		ParOrdenado nuevoPar = null;

		// Me fijo que los datos ingresados sean validos
		if (datosValidos()) {
			nuevoPar = new ParOrdenado(Double.parseDouble(this.textFieldX
					.getText()), Double.parseDouble(this.textFieldY.getText()));
			nuevoPar.setSelected(false);
		} else {
			limpiarCampos();
			return;
		}

		// Me fijo que no se haya ingresado el punto anteriormente
		if (correspondeAgregar(nuevoPar)) {
			this.soporteData.add(nuevoPar);
			Collections.sort(this.soporteData);
		}

		limpiarCampos();
		actualizarCantidadPuntosIngresados();
		textFieldX.requestFocus();

	}

	private void actualizarCantidadPuntosIngresados() {

		for (Controlador controller : this.main.getControladores()) {
			if (controller instanceof PolinomioControlador) {
				controller = (PolinomioControlador) controller;

				if (this.soporteData.size() != 0)
					((PolinomioControlador) controller)
							.getTxtCantidadPuntosIngresados().setText(
									String.valueOf(this.soporteData.size()));
				else {
					((PolinomioControlador) controller)
							.getTxtCantidadPuntosIngresados().setText("");
				}
			}
		}
	}

	private void limpiarCampos() {
		this.textFieldX.clear();
		this.textFieldY.clear();
	}

	private boolean correspondeAgregar(ParOrdenado nuevoPar) {

		Iterator<ParOrdenado> it = this.soporteData.iterator();

		while (it.hasNext()) {
			ParOrdenado par = it.next();
			if (par.getX().equals(nuevoPar.getX()))
				if (par.getY().equals(nuevoPar.getY()))
					return false;
		}

		return true;
	}

	@FXML
	private void handleLimpiarParesSeleccionados() {

		Iterator<ParOrdenado> it = this.soporteData.iterator();
		List<ParOrdenado> paresSeleccionados = new ArrayList<>();
		while (it.hasNext()) {
			ParOrdenado par = it.next();
			if (par.getSelected())
				paresSeleccionados.add(par);
		}

		soporteData.removeAll(paresSeleccionados);
		actualizarCantidadPuntosIngresados();
		this.textFieldX.requestFocus();

	}

	private boolean datosValidos() {
		String mensajeError = "";

		if (this.textFieldX.getText() == null
				|| this.textFieldX.getText().length() == 0)
			mensajeError += "Debe ingresar un valor para la abcisa del punto\n";

		if (this.textFieldY.getText() == null
				|| this.textFieldY.getText().length() == 0)
			mensajeError += "Debe ingresar un valor para la ordenada del punto\n";
		else {
			try {
				Double.parseDouble(this.textFieldX.getText());
			} catch (Exception e1) {
				mensajeError += "El formato ingresado para la abcisa no es valido\n";
			}
			try {
				Double.parseDouble(this.textFieldY.getText());
			} catch (Exception e2) {
				mensajeError += "El formato ingresado para la ordenada no es valido\n";
			}
		}

		if (mensajeError.length() == 0)
			return true;
		else {
			// Show the error message
			Dialogs.showErrorDialog(this.getMain().getEscenario(),
					mensajeError, "Por favor corrija los campos ingresados",
					"Campos invalidos");
			return false;

		}

	}

	/************************************************************/
	/********************* METODOS PRIVADOS *********************/
	/************************************************************/

	private void configurarTablaSoporte() {

		configurarColumnaCheckBox();
		configurarColumnaX();
		configurarColumnaY();

		// Resize las columnas
		tablaSoporte.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
		tablaSoporte.setEditable(true);
		tablaSoporte.setItems(this.getSoporteData());
		tablaSoporte.autosize();

	}

	private void configurarColumnaCheckBox() {
		columnaCheckbox
				.setCellValueFactory(new PropertyValueFactory<ParOrdenado, Boolean>(
						"selected"));

		columnaCheckbox
				.setCellFactory(new Callback<TableColumn<ParOrdenado, Boolean>, TableCell<ParOrdenado, Boolean>>() {

					public TableCell<ParOrdenado, Boolean> call(
							TableColumn<ParOrdenado, Boolean> p) {
						return new CheckBoxCell();
					}
				});
	}

	private void configurarColumnaY() {
		columnaY.setCellValueFactory(new PropertyValueFactory<ParOrdenado, Double>(
				"y"));

		columnaY.setCellFactory(new Callback<TableColumn<ParOrdenado, Double>, TableCell<ParOrdenado, Double>>() {

			public TableCell<ParOrdenado, Double> call(
					TableColumn<ParOrdenado, Double> param) {
				return new CeldaEditableDouble();
			}
		});
		columnaY.setOnEditCommit(new EventHandler<CellEditEvent<ParOrdenado, Double>>() {

			public void handle(CellEditEvent<ParOrdenado, Double> celda) {
				celda.getTableView().getItems()
						.get(celda.getTablePosition().getRow())
						.setY(celda.getNewValue());
			}
		});
	}

	private void configurarColumnaX() {
		columnaX.setCellValueFactory(new PropertyValueFactory<ParOrdenado, Double>(
				"x"));

		columnaX.setCellFactory(new Callback<TableColumn<ParOrdenado, Double>, TableCell<ParOrdenado, Double>>() {

			public TableCell<ParOrdenado, Double> call(
					TableColumn<ParOrdenado, Double> param) {
				return new CeldaEditableDouble();
			}
		});

		columnaX.setOnEditCommit(new EventHandler<CellEditEvent<ParOrdenado, Double>>() {

			public void handle(CellEditEvent<ParOrdenado, Double> celda) {
				celda.getTableView().getItems()
						.get(celda.getTablePosition().getRow())
						.setX(celda.getNewValue());
			}
		});
	}

}
